package com.jeasonzhao.report.decorator;

import com.jeasonzhao.commons.utils.Algorithms;
import com.jeasonzhao.commons.utils.DataTypes;
import com.jeasonzhao.commons.utils.RegexHelper;
import com.jeasonzhao.report.codes.BooleanOperations;
import com.jeasonzhao.report.dataset.DataCell;
import com.jeasonzhao.report.dataset.DataSet;
import com.jeasonzhao.report.dataset.DataSetFilter;
import com.jeasonzhao.report.dataset.RowInfo;
import com.jeasonzhao.report.dataset.RowInfoCollection;
import com.jeasonzhao.report.exceptions.ReportException;
import com.jeasonzhao.report.model.ObjectCollection;
import com.jeasonzhao.report.model.Report;
import com.jeasonzhao.report.model.ReportColumn;
import com.jeasonzhao.report.model.ReportParam;

public class DataSetFilterDecorator
{
    private DataSetFilterDecorator()
    {
    }

    public static int filterDimensions(Report report,DataSet dataset)
        throws ReportException
    {
        return filter(report,dataset,true);
    }

    public static int filterMeasures(Report report,DataSet dataset)
        throws ReportException
    {
        return filter(report,dataset,false);
    }

    private static int filter(Report report,DataSet dataset,boolean isInitColumn)
        throws ReportException
    {
        if(null == report
           || null == report.getDataSetFilters()
           || report.getDataSetFilters().size() < 1
           || null == dataset
           || null == dataset.getHeaderColumns()
           || null == report.getColumns())
        {
            return 0;
        }
        int nret = 0;
        for(int n = 0;n < report.getDataSetFilters().size();n++)
        {
            DataSetFilter filter = report.getDataSetFilters().elementAt(n);
            if(null == filter || filter.getValues() == null || filter.getColGuidId() == null || filter.getValues().size() < 1)
            {
                continue;
            }
            ReportColumn column = report.getColumns().getColumnByGuid(filter.getColGuidId());
            if(null == column)
            {
                continue;
            }
            if(isInitColumn == column.getColumnType().isCalcColumn())
            {
                continue;
            }
            nret += filterData(report,column,dataset,filter);
        }
        return nret;
    }

    private static int filterData(Report report,ReportColumn column,DataSet dataset,DataSetFilter filter)
    {
        java.util.ArrayList<Integer> cols = new java.util.ArrayList<Integer>();
        for(int ncolindex = 0;ncolindex < dataset.getHeaderColumns().size();ncolindex++)
        {
            if(filter.getColGuidId().equals(dataset.getHeaderColumn(ncolindex).getGuid()))
            {
                cols.add(ncolindex);
            }
        }
        if(cols.size() < 1)
        {
            return 0;
        }
        int nremoveCount = 0;
        RowInfoCollection rows = dataset.getRows();
        for(int nrow = 0;nrow < rows.size();nrow++)
        {
            RowInfo row = rows.get(nrow);
//            log.debug("Check ["+nrow+"].....>");
            for(int nx = 0;nx < cols.size();nx++)
            {
                int ncol = cols.get(nx);
                DataCell cell = row.get(ncol);
                if(cell == null || cell.getValue() == null ||
                   false == isMatch(filter.getBooleanOperation(),cell.getValue(),filter.getValues(),column.getDataType()))
                {
//                    log.debug("remove ["+nrow+"].....>");
                    rows.removeElementAt(nrow);
                    nrow = nrow - 1;
                    nremoveCount++;
                    break;
                }
            }
        }
//        log.debug(report + " 过滤【 " + column.getTitle() + " " + filter.getBooleanOperation().getName() + " " + filter.getValues().toString(",",false) + "】" +
//                  " 合计过滤掉 " + nremoveCount + " 行记录！");
//        log.debug(dataset.toHtml());
        return nremoveCount;
    }

    private static boolean isMatch(BooleanOperations op,Object cellValue,ObjectCollection chkValues,DataTypes dataType)
    {
        int n1 = op.equals(BooleanOperations.NotLike) || op.equals(BooleanOperations.Like) ? 0 :
            Algorithms.compare(dataType,cellValue,chkValues.get(0));
//        log.debug(op+"Compare "+value+"   "+chkValues.get(0)+"="+n1);
        if(op.equals(BooleanOperations.Equals))
        {
            return n1 == 0;
        }
        else if(op.equals(BooleanOperations.NotLike))
        {
            String strReg = chkValues.get(0).toString();
            String str = ReportParam.getFormatedValueString(cellValue);
            return false == RegexHelper.wildcardIgnoreCase(strReg,str);
        }
        else if(op.equals(BooleanOperations.Like))
        {
            String strReg = chkValues.get(0).toString();
            String str = ReportParam.getFormatedValueString(cellValue);
            return RegexHelper.wildcardIgnoreCase(strReg,str);
        }
        else if(op.equals(BooleanOperations.NotEquals))
        {
            return n1 != 0;
        }
        else if(op.equals(BooleanOperations.Great))
        {
            return n1 > 0;
        }
        else if(op.equals(BooleanOperations.GreatOrEquals))
        {
            return n1 >= 0;
        }
        else if(op.equals(BooleanOperations.Little))
        {
            return n1 < 0;
        }
        else if(op.equals(BooleanOperations.LittleOrEquals))
        {
            return n1 <= 0;
        }
        else if(op.equals(BooleanOperations.Between))
        {
            if(chkValues.size() < 2)
            {
                return false;
            }
            else
            {
                return n1 >= 0 && Algorithms.compare(dataType,cellValue,chkValues.get(1)) <= 0;
            }
        }
        else if(op.equals(BooleanOperations.NotBetween))
        {
            if(chkValues.size() < 2)
            {
                return false;
            }
            else
            {
                return n1 < 0 || Algorithms.compare(dataType,cellValue,chkValues.get(1)) > 0;
            }
        }
        else if(op.equals(BooleanOperations.In))
        {
            for(int n = 0;n < chkValues.size();n++)
            {
                if(Algorithms.compare(dataType,cellValue,chkValues.get(n)) == 0)
                {
                    return true;
                }
            }
            return false;
        }
        else if(op.equals(BooleanOperations.NotIn))
        {
            for(int n = 0;n < chkValues.size();n++)
            {
                if(Algorithms.compare(dataType,cellValue,chkValues.get(n)) == 0)
                {
                    return false;
                }
            }
            return true;
        }
        else
        {
            return false;
        }
    }
}
